package com.icongyou.enterprise.talent_analysis.service;

import com.icongyou.enterprise.data_aggregation.service.DataAggregationService;
import com.icongyou.enterprise.talent_analysis.entity.PortraitResponse;
import com.icongyou.enterprise.talent_analysis.service.impl.PortraitServiceImpl;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.HashMap;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;

/**
 * 画像服务测试
 */
@ExtendWith(MockitoExtension.class)
@DisplayName("画像服务测试")
class PortraitServiceImplTest {

    @Mock
    private DataAggregationService dataAggregationService;

    private PortraitServiceImpl portraitService;

    @BeforeEach
    void setUp() {
        portraitService = new PortraitServiceImpl(dataAggregationService);
    }

    @Test
    @DisplayName("计算默认画像 - 完整指标数据")
    void testComputeDefaultPortrait_WithCompleteMetrics() {
        // Arrange
        Map<String, Object> metrics = createCompleteMetrics();
        when(dataAggregationService.getStudentRawMetrics(
            anyString(), anyDouble(), anyInt(), anyInt()
        )).thenReturn(metrics);

        // Act
        PortraitResponse response = portraitService.computeDefaultPortrait("student-1");

        // Assert
        assertNotNull(response);
        assertEquals(6, response.getLabels().size());
        assertEquals(6, response.getScores().size());
        assertEquals(6, response.getDimensions().size());

        // 验证维度名称
        assertTrue(response.getLabels().contains("技术能力"));
        assertTrue(response.getLabels().contains("问题解决"));
        assertTrue(response.getLabels().contains("学习能力"));
        assertTrue(response.getLabels().contains("协作能力"));
        assertTrue(response.getLabels().contains("沟通能力"));
        assertTrue(response.getLabels().contains("执行能力"));

        // 验证分数在合理范围内 (0-5)
        response.getScores().forEach(score -> {
            assertTrue(score >= 0.0 && score <= 5.0, "分数应在0-5之间");
        });

        // 验证所有维度数据充足
        response.getDimensions().forEach(dim -> {
            assertFalse(dim.isInsufficientData(), "完整指标不应标记为数据不足");
        });
    }

    @Test
    @DisplayName("计算默认画像 - 部分指标缺失")
    void testComputeDefaultPortrait_WithPartialMetrics() {
        // Arrange - 只提供部分指标
        Map<String, Object> metrics = new HashMap<>();
        metrics.put("avg_course_score", 85.0);
        metrics.put("avg_assignment_score", 90.0);
        
        when(dataAggregationService.getStudentRawMetrics(
            anyString(), anyDouble(), anyInt(), anyInt()
        )).thenReturn(metrics);

        // Act
        PortraitResponse response = portraitService.computeDefaultPortrait("student-1");

        // Assert
        assertNotNull(response);
        assertEquals(6, response.getDimensions().size());

        // 技术能力维度应该有数据
        var techDimension = response.getDimensions().get(0);
        assertFalse(techDimension.isInsufficientData());
        assertTrue(response.getScores().get(0) > 0);

        // 其他维度应该标记为数据不足
        for (int i = 1; i < response.getDimensions().size(); i++) {
            assertTrue(response.getDimensions().get(i).isInsufficientData(),
                "缺失指标的维度应标记为数据不足");
            assertEquals(0.0, response.getScores().get(i),
                "数据不足的维度分数应为0");
        }
    }

    @Test
    @DisplayName("计算默认画像 - 所有指标缺失")
    void testComputeDefaultPortrait_WithNoMetrics() {
        // Arrange
        Map<String, Object> emptyMetrics = new HashMap<>();
        when(dataAggregationService.getStudentRawMetrics(
            anyString(), anyDouble(), anyInt(), anyInt()
        )).thenReturn(emptyMetrics);

        // Act
        PortraitResponse response = portraitService.computeDefaultPortrait("student-1");

        // Assert
        assertNotNull(response);
        assertEquals(6, response.getDimensions().size());

        // 所有维度都应标记为数据不足
        response.getDimensions().forEach(dim -> {
            assertTrue(dim.isInsufficientData(), "无数据时所有维度应标记为数据不足");
        });

        // 所有分数应为0
        response.getScores().forEach(score -> {
            assertEquals(0.0, score, "无数据时所有分数应为0");
        });
    }

    @Test
    @DisplayName("计算默认画像 - 边界值处理")
    void testComputeDefaultPortrait_BoundaryValues() {
        // Arrange - 使用边界值
        Map<String, Object> metrics = new HashMap<>();
        metrics.put("avg_course_score", 100.0);  // 最大值
        metrics.put("avg_assignment_score", 0.0);  // 最小值
        metrics.put("assignment_pass_rate", 1.0);  // 100%
        
        when(dataAggregationService.getStudentRawMetrics(
            anyString(), anyDouble(), anyInt(), anyInt()
        )).thenReturn(metrics);

        // Act
        PortraitResponse response = portraitService.computeDefaultPortrait("student-1");

        // Assert
        assertNotNull(response);
        
        // 验证分数计算正确且在有效范围内
        Double techScore = response.getScores().get(0);
        assertTrue(techScore >= 0.0 && techScore <= 5.0);
    }

    @Test
    @DisplayName("计算默认画像 - 权重调整验证")
    void testComputeDefaultPortrait_WeightAdjustment() {
        // Arrange - 模拟只有一个指标的情况
        Map<String, Object> metrics = new HashMap<>();
        metrics.put("avg_course_score", 80.0);
        
        when(dataAggregationService.getStudentRawMetrics(
            anyString(), anyDouble(), anyInt(), anyInt()
        )).thenReturn(metrics);

        // Act
        PortraitResponse response = portraitService.computeDefaultPortrait("student-1");

        // Assert
        var techDimension = response.getDimensions().get(0);
        assertFalse(techDimension.isInsufficientData());
        
        // 验证至少有一个维度有数据
        assertTrue(response.getDimensions().size() >= 1);
        assertTrue(techDimension.getDetails().stream()
            .anyMatch(detail -> detail.getWeight() > 0));
    }

    @Test
    @DisplayName("归一化分数 - 正常范围")
    void testNormalizeScore_NormalRange() {
        // Arrange
        Map<String, Object> metrics = createCompleteMetrics();
        when(dataAggregationService.getStudentRawMetrics(
            anyString(), anyDouble(), anyInt(), anyInt()
        )).thenReturn(metrics);

        // Act
        PortraitResponse response = portraitService.computeDefaultPortrait("student-1");

        // Assert
        // 技术能力: (85*0.6 + 90*0.4) / 100 * 5 = 4.35
        Double techScore = response.getScores().get(0);
        assertTrue(Math.abs(techScore - 4.35) < 0.1, 
            "技术能力分数计算应接近预期值");
    }

    @Test
    @DisplayName("计算维度详情 - 指标贡献度")
    void testComputeDimensionDetails_IndicatorContribution() {
        // Arrange
        Map<String, Object> metrics = createCompleteMetrics();
        when(dataAggregationService.getStudentRawMetrics(
            anyString(), anyDouble(), anyInt(), anyInt()
        )).thenReturn(metrics);

        // Act
        PortraitResponse response = portraitService.computeDefaultPortrait("student-1");

        // Assert
        var techDimension = response.getDimensions().get(0);
        assertNotNull(techDimension.getDetails());
        
        // 验证权重之和为100%
        double totalWeight = techDimension.getDetails().stream()
            .mapToDouble(ind -> ind.getWeight())
            .sum();
        assertEquals(1.0, totalWeight, 0.01, 
            "所有指标权重之和应为100%");
    }

    // ==================== Helper Methods ====================

    private Map<String, Object> createCompleteMetrics() {
        Map<String, Object> metrics = new HashMap<>();
        
        // 技术能力指标
        metrics.put("avg_course_score", 85.0);
        metrics.put("avg_assignment_score", 90.0);
        
        // 问题解决指标
        metrics.put("assignment_pass_rate", 0.8);
        metrics.put("submission_like_index", 5.0);
        
        // 学习能力指标
        metrics.put("course_completion_rate", 0.9);
        metrics.put("learning_speed_index", 1.2);
        metrics.put("rework_rate_inverse", 0.7);
        
        // 团队协作指标
        metrics.put("contribution_rate_avg", 0.8);
        metrics.put("avg_team_score", 88.0);
        
        // 沟通能力指标
        metrics.put("teacher_comment_rate", 0.5);
        metrics.put("discussion_count", 8.0);
        
        // 执行能力指标
        metrics.put("on_time_submission_rate", 0.9);
        metrics.put("deadline_miss_inverse", 0.95);
        
        return metrics;
    }
}
